package com.ruoyi;

import com.ruoyi.activiti.utils.ExpressionKeyExtractor;
import com.ruoyi.activiti.utils.GatewayConditionService;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.*;

@SpringBootTest
public class ActivitiTest1 {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private GatewayConditionService gatewayConditionService;

    @Autowired
    private ExpressionKeyExtractor expressionKeyExtractor;

    @Autowired
    private HistoryService historyService;

    /*
    * 部署流程
    * */
    @Test
    public void deploy() {
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("./BPMN/contract.bpmn")
                .category("contract11")
                .key("contract_11")
                .name("合同申请11")
                .deploy();
        System.out.println(deployment.getId()+"----"+deployment.getName());
    }

    /*
    * 查询流程定义
    * */
    @Test
    public void getDeployment() {
        List<Deployment> list = repositoryService.createDeploymentQuery().list();
        list.forEach(item -> {
            System.out.println("id:"+item.getId()+",name:"+item.getName()+
                    ",key:"+item.getKey()+",deploymentTime:"+item.getDeploymentTime());
        });
    }

    /*
    * 删除流程
    * */
    @Test
    public void delDefinition() {
        // 用act_re_deployment ID_字段
        String id = "5d5f3bb6-608e-11f0-aab7-0250f2000002";
        repositoryService.deleteDeployment(id);
    }

    /*
    * 启动流程
    * */
    @Test
    public void startDeployment() {
        ProcessInstance start = runtimeService.createProcessInstanceBuilder()
                .businessKey("bz_contract33")  // 这里可以写上业务表的唯一ID
                .name("报装合同申请33")
                .processDefinitionId("Process_1:3:01c524f5-609b-11f0-a3c9-0250f2000002")
                .start();
        System.out.println(start.getId()+"----"+start.getName()+"----"+start.getProcessDefinitionId());
    }

    /*
    * 查询所有任务
    * */
    @Test
    public void getAllTasks() {
        List<Task> list = taskService.createTaskQuery().list();
        list.forEach(item -> {
            System.out.println("id:"+item.getAssignee()+",name:"+item.getName()+",实例Id:"+item.getProcessInstanceId());
        });
    }
    /*
    * 查询我的待办
    * */
    @Test
    public void selfTasks() {
        ArrayList<String> roles = new ArrayList<>();
        roles.add("cwzj");
        List<Task> list = taskService.createTaskQuery()
                .processInstanceId("5b54f6fa-608f-11f0-ace2-0250f2000002")
                .or()
                .taskAssignee("songjiang")
                .taskCandidateUser("songjiang")
                .taskCandidateGroupIn(roles)
                .endOr()
                .list();
        list.forEach(item -> {
            System.out.println("id:"+item.getAssignee()+",name:"+item.getName()+",实例Id:"+item.getProcessInstanceId());
        });
    }
    /*
    * 完成任务
    * */
    @Test
    public void completeTasks() {
        HashMap<String, Object> hm = new HashMap<>();
        hm.put("approve",true);
       // hm.put("day",3);
        taskService.complete("555f469d-609b-11f0-8ac0-0250f2000002",hm);
    }

    /*
    * 查询已经结束的流程
    * */
    @Test
    public void completeHisTasks() {
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId("df586fec-639f-11f0-99a0-0250f2000002") // 只查询已结束的流程
                .finished()
                .orderByProcessInstanceEndTime().desc()  // 按结束时间倒序
                .list();
        System.out.println("已结束流程的个数:"+list.size());
        list.forEach(item -> {
            System.out.println(item.getId()+"----"+item.getName()+"----"+item.getBusinessKey());
        });
    }
    /**
    * 结束任务
    * */
    @Test
    public void killTask() {
        //  当前任务
        Task task = taskService.createTaskQuery().taskId("d7d602ec-65dd-11f0-be4d-0250f2000002").singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        List<EndEvent> endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        FlowNode endFlowNode = endEventList.get(0);
        FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());

        //  临时保存当前活动的原始方向
        List originalSequenceFlowList = new ArrayList<>();
        originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
        //  清理活动方向
        currentFlowNode.getOutgoingFlows().clear();

        //  建立新方向
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(currentFlowNode);
        newSequenceFlow.setTargetFlowElement(endFlowNode);
        List newSequenceFlowList = new ArrayList<>();
        newSequenceFlowList.add(newSequenceFlow);
        //  当前节点指向新的方向
        currentFlowNode.setOutgoingFlows(newSequenceFlowList);

        //  完成当前任务
        taskService.complete(task.getId());

        //  可以不用恢复原始方向，不影响其它的流程
//        currentFlowNode.setOutgoingFlows(originalSequenceFlowList);

    }
    /**
    * 查询用户节点后面的网关类型
    * */
    @Test
    public FlowElement taskType() {
        // 1. 获取当前任务
        Task task = taskService.createTaskQuery().taskId("d7d602ec-65dd-11f0-be4d-0250f2000002").singleResult();
        String processDefinitionId = task.getProcessDefinitionId();

        // 2. 获取BPMN模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Process process = bpmnModel.getMainProcess();

        // 3. 获取当前任务节点
        FlowElement currentElement = process.getFlowElement(task.getTaskDefinitionKey());
        if (!(currentElement instanceof UserTask)) {
            throw new IllegalArgumentException("当前节点不是用户任务");
        }
        String nextElementType = "";
        FlowElement targetElement = null;
        // 4. 获取所有出线并解析目标节点
        List<SequenceFlow> outgoingFlows = ((UserTask) currentElement).getOutgoingFlows();
        if (outgoingFlows.isEmpty()) {
            nextElementType = "END_EVENT"; // 无出线说明流程结束
        }
        System.out.println("获取所有出线并解析目标节点:"+outgoingFlows.size());
        // 5. 遍历出线（通常用户任务只有一条默认出线）
        for (SequenceFlow flow : outgoingFlows) {
             targetElement = process.getFlowElement(flow.getTargetRef());

            // 6. 判断目标节点类型
            if (targetElement instanceof ExclusiveGateway) {
                nextElementType = "EXCLUSIVE_GATEWAY";
            } else if (targetElement instanceof InclusiveGateway) {
                nextElementType = "INCLUSIVE_GATEWAY";
            } else if (targetElement instanceof ParallelGateway) {
                nextElementType = "PARALLEL_GATEWAY";
            } else if (targetElement instanceof UserTask) {
                nextElementType = "USER_TASK";
            } else if (targetElement instanceof EndEvent) {
                nextElementType = "END_EVENT";
            }
            // 其他类型：ServiceTask, ScriptTask, CallActivity 等...
        }
        System.out.println("下个节点类型:"+nextElementType);
        return targetElement;
    }

    /**
     * 分析流程中的网关条件
     */
    @Test
    public void analyzeProcessGateways() {
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId("levave_1:2:01bcaf60-637d-11f0-8e74-0250f2000002")
                .singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel("levave_1:2:01bcaf60-637d-11f0-8e74-0250f2000002");

        // 查找所有网关
        List<Gateway> gateways = bpmnModel.getMainProcess().findFlowElementsOfType(Gateway.class);

        for (Gateway gateway : gateways) {
            System.out.println("分析网关: " + gateway.getId() + " (" + gateway.getClass().getSimpleName() + ")");

            // 获取条件表达式
            Map<String, String> conditions = gatewayConditionService.getGatewayConditions(
                    "levave_1:2:01bcaf60-637d-11f0-8e74-0250f2000002", gateway.getId());

            conditions.forEach((flowId, expr) -> {
                System.out.println(" - 序列流 " + flowId + ": " + expr);
            });

            // 验证网关配置
            GatewayConditionService.GatewayValidationResult validation =
                    gatewayConditionService.validateGatewayConditions("levave_1:2:01bcaf60-637d-11f0-8e74-0250f2000002", gateway.getId());

            System.out.println("验证结果: " + (validation.isValid() ? "有效" : "无效"));
            if (!validation.isValid()) {
                System.out.println("问题: 网关有条件表达式但没有设置默认流");
            }
        }
    }

    /**
     * 获取网关的详细信息
     */
    @Test
    public void printGatewayDetails() {
        FlowElement flowElement = taskType();
        System.out.println(flowElement.getId()+"----"+flowElement.getName()+"---"+flowElement.getExtensionElements());
        List<GatewayConditionService.SequenceFlowCondition> conditions =
                gatewayConditionService.getSequenceFlowConditions("levave_1:2:01bcaf60-637d-11f0-8e74-0250f2000002", "Gateway_1y22560");

        System.out.println("网关Gateway_1y22560 " + " 的序列流条件:");
        for (GatewayConditionService.SequenceFlowCondition condition : conditions) {
            System.out.println("ID: " + condition.getId());
            System.out.println("名称: " + condition.getName());
            System.out.println("目标: " + condition.getTargetRef());
            System.out.println("表达式: " + (condition.getExpression() != null ? condition.getExpression() : "无"));
            System.out.println("类型: " + condition.getExpressionType());
            System.out.println("是否默认: " + condition.isDefaultFlow());
            System.out.println("---------------------");
        }

        Set<String> strings = expressionKeyExtractor.extractKeysFromExpression(conditions.get(0).getExpression());
        System.out.println(strings.toArray()[0]);
    }

    @Test
    public void defKey() {
        Task task = taskService.createTaskQuery().taskId("63bcd981-65fc-11f0-99af-0250f2000002")
                .singleResult();
        System.out.println(task.getTaskDefinitionKey());
    }

    /**
     * 高亮显示路程历史
     */
    @Test
    public void getHighlight(){
        try {
            // 获取一条流程实例历史
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId("631734cf-6699-11f0-852a-0250f2000002")
                    .singleResult();
            // 根据流程定义 key 获取 BMPN
            BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
            // 获取流程
            Process process = bpmnModel.getProcesses().get(0);
            // 获取所有流程 FlowElement 的信息，就是所有bpmn的节点
            Collection<FlowElement> flowElements = process.getFlowElements();

            /**
             * 这个 map 中的 key 就是 开始节点和结束节点的编号拼起来的字符串，
             * value 就是开始节点和结束节点的连线，到时候我们根据开始节点和结束节点
             * 就可以获取到需要高亮的连线
             */
            Map<String,String> map = new HashMap<String,String>();
            for (FlowElement flowElement : flowElements) {
                // 判断是否是线条
                if(flowElement instanceof SequenceFlow){
                    SequenceFlow sequenceFlow = (SequenceFlow)flowElement;
                    String ref = sequenceFlow.getSourceRef();
                    String targetRef = sequenceFlow.getTargetRef();
                    /**
                     * 保存开始节点和结束节点，与它们之间连线的对应关系
                     * key: 开始节点 编号 + 结束节点 编号
                     * value: 连线编号
                     */
                    map.put(ref+targetRef,sequenceFlow.getId());
                }
            }

            /**
             * 获取已经完成的全部流程历史节点
             */
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId("631734cf-6699-11f0-852a-0250f2000002")
                    .list();
            /**
             * 将各个历史节的开始节点和结束几点的编号两两对应起来，
             * 就可以从上面的 map 中获取到需要高亮的连线
             */
            Set<String> keyList = new HashSet<String>();
            for (HistoricActivityInstance i : list) {
                for (HistoricActivityInstance j : list) {
                    if(i != j){
                        keyList.add(i.getActivityId()+j.getActivityId());
                    }
                }
            }

            // 获取高亮连线 id
            Set<String> highLine = new HashSet<String>();
            // 根据已经完成的（开始节点编号+结束节点编号）组成的 key 获取需要高亮的连线编号
            keyList.forEach(s -> highLine.add(map.get(s)));


            // 获取已经完成的节点
            List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId("631734cf-6699-11f0-852a-0250f2000002")
                    .finished()
                    .list();

            // 已经完成的节点高亮
            Set<String> highPoint = new HashSet<>();
            // 保存已经完成的流程节点编号
            listFinished.forEach(s -> highPoint.add(s.getActivityId()));

            // 获取代办节点
            List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId("631734cf-6699-11f0-852a-0250f2000002")
                    .unfinished()
                    .list();

            // 代办的节点高亮
            Set<String> waitingToDo = new HashSet<>();
            // 保存需要代办的节点编号
            listUnFinished.forEach(s -> waitingToDo.add(s.getActivityId()));


            // 获取当前用户完成的任务
            List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
                    .taskAssignee("zhangsan")
                    .processInstanceId("631734cf-6699-11f0-852a-0250f2000002")
                    .finished()
                    .list();

            // 当前用户完成的高亮
            Set<String> iDo = new HashSet<String>();
            // 保存用户完成的节点编号
            taskInstanceList.forEach(s -> iDo.add(s.getTaskDefinitionKey()));

            Map<String,Object> reMap = new HashMap<String, Object>();
            // 高亮已经完成的节点
            reMap.put("highPoint",highPoint);
            // 高亮连线节点编号
            reMap.put("highLine", highLine);
            // 高亮代办节点编号
            reMap.put("waitingToDo", waitingToDo);
            // 高亮当前用户完成的节点编号
            reMap.put("iDo",iDo);

            System.out.println("节点组装后:"+reMap);
        } catch (Exception e) {
            System.out.println("报错了"+e.getMessage());
        }
    }

    @Test
    public void historyTask() {
        // 获取历史流程实例
        List<HistoricTaskInstance> list = historyService
                .createHistoricTaskInstanceQuery()
                .processDefinitionKey("levave_1")
                .taskAssignee("zhagnsan")
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list();
        list.forEach(item -> {
            System.out.println(item.getId()+"--"+item.getName()+"--"+item.getAssignee()+"--"+item.getProcessInstanceId()+"--"+item.getTaskDefinitionKey()+"--"+item.getTaskDefinitionKey()+"--"+item.getTaskDefinitionKey()+"--"+item.getParentTaskId());
        });
    }
    @Test
    public void Candidate() {
        Task task = taskService.createTaskQuery()
                .processInstanceId("4c1d5688-679e-11f0-800d-0250f2000002")
                .singleResult();
        // 获取任务的所有身份链接
        List<IdentityLink> allLinks = taskService.getIdentityLinksForTask(task.getId());
        allLinks.forEach(identityLink -> {
            System.out.println(identityLink.getUserId()+"---"+identityLink.getGroupId()+"----"+identityLink.getGroupId()+"---"+identityLink.getType());
        });
    }

}
